﻿//-------------------------------------
// WBFSSync - WBFSSync.exe
//
// Copyright 2009 Caian (ÔmΣga Frøst) <frost.omega@hotmail.com> :
//
// WBFSSync is Licensed under the terms of the Microsoft Reciprocal License (Ms-RL)
//
// ProgramUpdate.cs:
//
// Classe que controla a verificação e download de atualizações, em desenvolvimento
//
//-------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Threading;
using System.ComponentModel;
using System.Windows.Forms;

namespace WBFSSync
{
    enum UpdateMode : byte
    {
        Off,
        OnExecute,
        OnceADay,
        OnceAWeek,
    }

    struct COREFILE
    {
        public String Path;
        public long Size;
        public String MD5;

        public COREFILE(string p, long s, string md5)
        {
            Path = p;
            Size = s;
            MD5 = md5;
        }
    }

    struct LANGUAGEFILE
    {
        public String Path;
        public long Size;

        public LANGUAGEFILE(string p, long s)
        {
            Path = p;
            Size = s;
        }
    }

    class ProgressHolder
    {
        public ProgressIndicator progress = null;
        public Boolean completed = false;
        public AsyncCompletedEventArgs e = null;
        public long received = 0;

        public ProgressHolder()
        {

        }

        public ProgressHolder(ProgressIndicator p)
        {
            progress = p;
        }
    }

    static class ProgramUpdate
    {
        //------------------- Constantes
        public const String UpdateHost = @"https://wbfssync.svn.codeplex.com/svn/";
        public const String UpdateFile = UpdateHost + "UPDATE/UPDATE.inf";

        public const String UpdateFolder = "Update\\";

        //------------------- Configurações
        public static UpdateMode UpdateMode = UpdateMode.Off;
        public static bool NotifyOnly = true;
        public static DateTime LastUpdate = DateTime.Now;

        //------------------- SVN

        public static List<COREFILE> CoreFiles = new List<COREFILE>();
        public static List<LANGUAGEFILE> LanguageFiles = new List<LANGUAGEFILE>();
        //SkinFiles ainda não está implementado
        
        public static Int32 Version = -1;
        public static String SVersion = "";

        //-------------------
        public static Boolean UpdatedToday 
        { 
            get 
            { 
                return LastUpdate.DayOfYear >= DateTime.Now.DayOfYear; 
            } 
        }
        public static Boolean UpdatedThisWeek
        {
            get
            {
                return LastUpdate.DayOfYear + (int)LastUpdate.DayOfWeek >= DateTime.Now.DayOfYear;
            }
        }

        public static int CurrentVersion
        {
            get
            {
                Version vThisVersion = new Version(Application.ProductVersion);
                return (vThisVersion.Major * 1000) + (vThisVersion.Minor * 100) + vThisVersion.Build;
            }
        }

        public static bool UpdateActive = false;

        //------------------- Rotinas

        //------------------- Atualiza a lista de arquivos para download e retorna a versão
        public static int GetSubversionList()
        {
            //
            CoreFiles.Clear();
            LanguageFiles.Clear();
            Version = -1;
            SVersion = "";

            //-------
            int r = -1;

            HttpWebRequest request = null;
            HttpWebResponse response = null;
            Stream stream = null;
            StreamReader reader = null;

            try
            {
                request = (HttpWebRequest)WebRequest.Create(UpdateFile);
                response = (HttpWebResponse)request.GetResponse();
                stream = response.GetResponseStream();
                reader = new StreamReader(stream);

                string update = reader.ReadToEnd();
                string[] lines = update.Replace("\r", "").Split('\n');
                foreach (string line in lines)
                {
                    string arg;
                    if (line.StartsWith("VERSION:"))
                    {
                        arg = line.Substring(8).Trim();
                        string[] sv = arg.Split('.');
                        
                        int v = 0;
                        v += int.Parse(sv[0]) * 1000;
                        v += int.Parse(sv[1]) * 100;
                        v += int.Parse(sv[2]);

                        Version = v;
                        SVersion = arg;

                    }
                    else if (line.StartsWith("COREFILE:"))
                    {
                        arg = line.Substring(9).Trim();
                        string[] corefile = arg.Split('|');

                        CoreFiles.Add(new COREFILE(corefile[0], long.Parse(corefile[1]), corefile[3]));
                    }
                    else if (line.StartsWith("LANGUAGE:"))
                    {
                        arg = line.Substring(9).Trim();
                        string[] langfile = arg.Split('|');

                        LanguageFiles.Add(new LANGUAGEFILE(langfile[0], long.Parse(langfile[1])));
                    }
                    /* else if (line.StartsWith("SKIN:"))
                    {
                    }
                    */
                }

                r = Version;
            }
            catch (WebException e)
            {
                Log.LogException(e);
                Log.LogLine(Language.log_update_cant_get_version, LogMessageType.Error);
            }
            catch (Exception e)
            {
                Log.LogException(e);
            }

            //---------------------

            if (stream != null)
            {
                stream.Close();
                stream = null;
            }

            if (response != null)
            {
                response.Close();
                response = null;
            }

            if (request != null)
            {
                request = null;
            }

            return r;
        }

        //------------------- Baixa um arquivo com contador de progresso
        //nota: ele não vai alterar o valor de progress.total
        public static int DownloadFile(string url, string fileout, ProgressIndicator progress)
        {
            WebClient client = new WebClient();
            ProgressHolder holder = new ProgressHolder(progress);

            client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
            client.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(client_DownloadFileCompleted);
            client.DownloadFileAsync(new Uri(url), fileout, holder);

            while (!holder.completed)
            {
                if (progress.Cancel) client.CancelAsync();
                Thread.Sleep(1);
            }

            if((holder.e != null) && (holder.e.Error != null))
            {
                Log.LogException(holder.e.Error);
                return -1;
            }
            else
            {
                return 0;
            }
        }

        static void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            ProgressHolder p = (ProgressHolder)e.UserState;
            p.completed = true;
            p.e = e;
        }

        static void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            ProgressHolder p = (ProgressHolder)e.UserState;
            p.progress.Progress += e.BytesReceived - p.received; //Adiciona o progresso relativo
            p.received = e.BytesReceived;
        }
    }
}
